package com.h3bpm.starcharge.controller.bpm;

import OThinker.Common.Organization.Models.User;
import OThinker.H3.Entity.Data.Attachment.Attachment;
import OThinker.H3.Entity.Instance.Data.IInstanceDataItem;
import OThinker.H3.Entity.Instance.Data.InstanceData;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.*;
import com.h3bpm.base.util.CharsetUtil;
import com.h3bpm.starcharge.common.bean.*;
import com.h3bpm.starcharge.common.uitl.*;
import com.h3bpm.starcharge.service.bpm.StarChargeBpmService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.h3bpm.base.exception.GlobalErrorConst;
import com.h3bpm.base.res.ResBody;
import com.h3bpm.starcharge.param.workflow.StartWorkflowNewParam;
import com.h3bpm.starcharge.ret.workflow.StartWorkflowNewRet;
import com.h3bpm.starcharge.service.WorkflowCommentService;
import OThinker.H3.Controller.ControllerBase;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * 流程控制器
 *
 * @author llongago
 * @date 2019/2/18
 */
@Controller
@RequestMapping("/starCharge/workFlow")
public class WorkFlowController extends ControllerBase {

    private static final Logger LOGGER = LoggerFactory.getLogger(WorkFlowController.class);

    @Override
    public String getFunctionCode() {
        return null;
    }

    @Autowired
    private StarChargeBpmService starChargeBpmService;

    @Autowired
    private WorkflowCommentService workflowCommentService;

    /**
     * 发起流程
     *
     * @param workflowCode 流程模板编码
     * @param userCode     用户编码
     * @param finishStart  是否结束第一个活动
     * @param paramValues  普通参数（JSON格式）
     * @param zbValues     子表参数（JSON格式）
     * @param files        附件
     * @return StartWorkflowNewRet
     */
    @RequestMapping(value = "/start", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    @ResponseBody
    public RetResult startWorkFlow(@RequestParam String workflowCode,
                                   @RequestParam String userCode,
                                   @RequestParam String finishStart,
                                   @RequestParam(required = false) String paramValues,
                                   @RequestParam(required = false) String zbValues,
                                   @RequestParam(value = "files", required = false) MultipartFile[] files) {
        String paramValue = "";
        String zbValue = "";
        String param;
        try {
            if (null != paramValues && !"".equals(paramValues)) {
                paramValue = ScitParamUtil.paramToJson(paramValues);
            }
            if (null != zbValues && !"".equals(zbValues)) {
                zbValue = ScitParamUtil.zbParamToJson(zbValues);
            }
            // 子表参数拼接
            StringBuilder sb = new StringBuilder();
            sb.append(paramValue);
            StringBuilder bs = new StringBuilder();
            bs.append(zbValue);
            if (null != paramValues && null != zbValues) {
                sb.deleteCharAt(sb.length() - 1).append(",");
                bs.delete(0, 1);
            }
            param = sb.toString() + bs.toString();
            StartWorkflowNewParam workflowParam = new StartWorkflowNewParam(workflowCode, userCode, finishStart, param);
            StartWorkflowNewRet result = starChargeBpmService.startWorkflowNew(workflowParam);
            if (result.isSuccess() && files != null) {
                String instanceId = result.getInstanceID();
                InstanceData instanceData = new InstanceData(getEngine(), instanceId, User.AdministratorID);
                uploadFile(files, workflowCode, instanceData.getBizObject().getObjectID());
            }
            if (!result.isSuccess()) {
                return RetResponse.makeErrRsp(result.getMessage());
            }
            Map<String, Object> map = new HashMap<>(2);
            map.put("instanceId", result.getInstanceID());
            return RetResponse.makeOKRsp(map);
        } catch (Exception e) {
            return ErrorUtil.generalException(e);
        }
    }

    /**
     * 发起流程（参数不需要处理）
     *
     * @param workflowCode 流程模板编码
     * @param userCode     用户编码
     * @param param        流程参数
     * @return RetResult
     */
    @RequestMapping(value = "/goStart", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    @ResponseBody
    public RetResult startWorkFlow(@RequestParam String workflowCode,
                                   @RequestParam String userCode,
                                   @RequestParam(required = false) String param) {
        StartWorkflowNewParam workflowParam = new StartWorkflowNewParam(workflowCode, userCode, "true", param);
        StartWorkflowNewRet result = starChargeBpmService.startWorkflowNew(workflowParam);
        if (!result.isSuccess()) {
            return RetResponse.makeErrRsp(result.getMessage());
        }
        Map<String, Object> map = new HashMap<>(2);
        map.put("instanceId", result.getInstanceID());
        return RetResponse.makeOKRsp(map);
    }

    /**
     * 添加附件
     *
     * @param workflowCode  流程模板编码
     * @param instanceId    流程id
     * @param attrField     附件字段
     * @param attrUrl       附件url
     * @param fileName      附件名称
     * @return RetResult
     * @throws Exception
     */
    @RequestMapping(value = "/addAttr", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    @ResponseBody
    public RetResult test(@RequestParam String workflowCode,
                          @RequestParam String instanceId,
                          @RequestParam String attrField,
                          @RequestParam String attrUrl,
                          @RequestParam String fileName) throws Exception {
        if ("".equals(attrUrl) || "".equals(attrField)) {
            return RetResponse.makeErrRsp("参数异常!");
        }
        URL url = new URL(attrUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        // 设置超时间为3秒
        conn.setConnectTimeout(3 * 1000);
        // 防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
        InstanceData instanceData = new InstanceData(getEngine(), instanceId, User.AdministratorID);
        uploadSingleFile(conn, workflowCode, instanceData.getBizObject().getObjectID(), attrField, fileName);
        return RetResponse.makeOKRsp();
    }

    /**
     * 修改流程参数
     *
     * @param instanceId  流程id
     * @param paramValues 基本参数
     * @param zbValues    子表参数
     * @return RetResult
     */
    @RequestMapping(value = "/edit", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    @ResponseBody
    public RetResult editWorkflow(@RequestParam String instanceId,
                                  @RequestParam(required = false) String paramValues,
                                  @RequestParam(required = false) String zbValues) {
        try {
            InstanceData instanceData = new InstanceData(getEngine(), instanceId, User.AdministratorID);
            Gson gson = new Gson();
            JsonParser parser = new JsonParser();
            // 基本参数
            if (null != paramValues) {
                JsonArray jsonArray = parser.parse(paramValues).getAsJsonArray();
                for (JsonElement json : jsonArray) {
                    WorkFlowUniversalParam universalParam = gson.fromJson(json, WorkFlowUniversalParam.class);
                    IInstanceDataItem item = instanceData.getItem(universalParam.getName());
                    if (item != null) {
                        item.setValue(universalParam.getValue());
                    }
                }
                instanceData.Submit();
            }
            // 子表参数
            if (null != zbValues) {
                JsonArray jsonArray = parser.parse(zbValues).getAsJsonArray();
                for (JsonElement json : jsonArray) {
                    WorkFlowZbParam zbValue = gson.fromJson(json, WorkFlowZbParam.class);
                    IInstanceDataItem item = instanceData.getItem(zbValue.getName());
                    if (null != item) {
                        for (int i = 0; i < zbValue.getValue().size(); i++) {
                            StringBuilder sb = new StringBuilder();
                            for (int j = 0; j < zbValue.getValue().get(i).size(); j++) {
                                sb.append(zbValue.getValue().get(i).get(j).getName()).append(" = ").append("'").append(zbValue.getValue().get(i).get(j).getValue()).append("' ,");
                            }
                            String s = sb.deleteCharAt(sb.length() - 1).toString();
                            StringBuilder bs = new StringBuilder();
                            bs.append("update I_").append(zbValue.getName()).append(" set ").append(s).append(" where ParentObjectID = '")
                                    .append(instanceData.getBizObject().getObjectID()).append("' and ParentIndex = ").append(i);
                            SqlUtils.doNoQuery(bs.toString());
                        }
                    }
                }
            }
            return RetResponse.makeOKRsp();
        } catch (Exception e) {
            return ErrorUtil.generalException(e);
        }
    }

    @RequestMapping(value = "/Mobile/comments", method = RequestMethod.GET)
    @ResponseBody
    public ResBody getComments(@RequestParam String instanceId) {
        if (StringUtils.isEmpty(instanceId)) {
            LOGGER.error("InstanceId can't be null or empty.");

            return ResBody.buildFailResBody(GlobalErrorConst.buildBizErrorConst("report.configNotExist"));
        }

        return workflowCommentService.getComments(instanceId);
    }

    @RequestMapping(value = "/Mobile/addComment", method = RequestMethod.POST)
    @ResponseBody
    public ResBody addComment(@RequestBody WorkflowComment comment) {
        return workflowCommentService.addComment(comment);
    }

    @RequestMapping(value = "/Mobile/uploadAttachment", method = RequestMethod.POST)
    @ResponseBody
    public ResBody uploadAttachment(@RequestParam("file") MultipartFile file, boolean uploadByImage) {
        return workflowCommentService.uploadAttachment(file, uploadByImage);
    }

    /**
     * bpm上传附件到流程
     *
     * @param files        文件
     * @param workflowCode 流程编码
     * @param objectID     流程id
     * @throws Exception
     */
    private void uploadFile(MultipartFile[] files, String workflowCode, String objectID) throws Exception {
        int allowedSize = FileUploadUtil.getAllowedMaxSize(false);
        for (MultipartFile file : files) {
            // 超过限制的文件不上传
            if (file.getSize() > allowedSize) {
                continue;
            }
            String attachmentId = UUID.randomUUID().toString();
            ByteArrayOutputStream baout = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            InputStream stream = file.getInputStream();
            String charset = CharsetUtil.getCharset(stream);

            int i;
            while ((i = stream.read(bytes, 0, 1024)) > 0) {
                baout.write(bytes, 0, i);
            }

            byte[] contents = baout.toByteArray();
            if (file.getOriginalFilename().endsWith(".txt")) {
                contents = (new String(contents, charset)).getBytes("utf-8");
            }

            Attachment attachment = new Attachment();
            attachment.setObjectID(attachmentId);
            attachment.setContent(contents);
            attachment.setContentType(file.getContentType());
            attachment.setCreatedBy(User.AdministratorID);
            attachment.setCreatedTime(new Date());
            attachment.setFileName(file.getOriginalFilename());
            attachment.setLastVersion(true);
            attachment.setModifiedTime(new Date());
            // 流程编码
            attachment.setBizObjectSchemaCode(workflowCode);
            attachment.setContentLength((int) file.getSize());
            // 流程id
            attachment.setBizObjectId(objectID);
            attachment.setDataField("attr");
            getEngine().getBizObjectManager().AddAttachment(attachment);
        }
    }

    /**
     * bpm上传附件到流程
     *
     * @param conn         文件
     * @param workflowCode 流程编码
     * @param objectID     流程id
     * @param attrFiled    附件字段
     * @param fileName     文件名
     * @throws Exception
     */
    private void uploadSingleFile(HttpURLConnection conn, String workflowCode, String objectID, String attrFiled, String fileName) throws Exception {
        int allowedSize = FileUploadUtil.getAllowedMaxSize(false);
        // 超过限制的文件不上传
        if (conn.getContentLength() > allowedSize) {
            return;
        }
        String attachmentId = UUID.randomUUID().toString();
        ByteArrayOutputStream baout = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        InputStream stream = conn.getInputStream();
        String charset = CharsetUtil.getCharset(stream);

        int i;
        while ((i = stream.read(bytes, 0, 1024)) > 0) {
            baout.write(bytes, 0, i);
        }

        byte[] contents = baout.toByteArray();
        if (fileName.endsWith(".txt")) {
            contents = (new String(contents, charset)).getBytes(UTF_8);
        }

        Attachment attachment = new Attachment();
        attachment.setObjectID(attachmentId);
        attachment.setContent(contents);
        attachment.setContentType(conn.getHeaderField("Content-Type"));
        attachment.setCreatedBy(User.AdministratorID);
        attachment.setCreatedTime(new Date());
        attachment.setFileName(fileName);
        attachment.setLastVersion(true);
        attachment.setModifiedTime(new Date());
        // 流程编码
        attachment.setBizObjectSchemaCode(workflowCode);
        attachment.setContentLength(conn.getContentLength());
        // 流程id
        attachment.setBizObjectId(objectID);
        attachment.setDataField(attrFiled);
        getEngine().getBizObjectManager().AddAttachment(attachment);
    }

    @RequestMapping(value = "/sendEndMessage")
    @ResponseBody
    public ResBody sendEndMessage(@RequestParam String instanceId) {
        if (StringUtils.isEmpty(instanceId)) {
            LOGGER.error("InstanceId can't be null or empty.");

            return ResBody.buildFailResBody(GlobalErrorConst.buildBizErrorConst("report.configNotExist"));
        }

        return workflowCommentService.sendEndMessage(instanceId);
    }

    /**
     * 获取流程明细
     *
     * @param instanceId 流程id
     * @param userCode   用户账号
     * @param password   密码
     * @return RetResult
     */
    @RequestMapping(value = "/instanceInfo")
    @ResponseBody
    public RetResult getInstanceInfo(@RequestParam String instanceId, @RequestParam(required = false, defaultValue = "administrator") String userCode, @RequestParam(required = false, defaultValue = "000000") String password) {
        try {
            String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
            String json = "{\"isMobile\":\"1\",\"userCode\":\"" + userCode + "\",\"password\":\"" + Md5Util.getMD5(password, false, 32) + "\"}";
            HttpResponse response = HttpRequest.post(url + "/Portal/Mobile/LoginIn")
                    .body(json)
                    .execute();
            String loginResult = response.body();
            if (!loginResult.contains("请求成功")) {
                return RetResponse.makeErrRsp("登录失败");
            }
            Map<String, Object> map = new HashMap<>(8);
            String workflowObject = starChargeBpmService.getWorkItemObject(instanceId);
            if ("".equals(workflowObject)) {
                map.put("detailInfo", null);
            } else {
                String detailInfo = HttpRequest.get(url + "/Portal/MvcDefaultSheet/OnLoad?localLan=zh_CN&Command=load&Lang=zh_cn&WorkItemID=" + workflowObject).cookie("h3bpmportal=" + response.getCookie("JSESSIONID")).execute().body();
                map.put("detailInfo", JSONObject.parseObject(detailInfo));
            }
            String stateBody = HttpRequest.get(url + "/Portal/Mobile/LoadInstanceState?instanceID=" + instanceId).cookie("h3bpmportal=" + response.getCookie("JSESSIONID")).execute().body();
            if (!stateBody.contains("请求成功")) {
                return RetResponse.makeErrRsp("流程模板不存在或未发布！");
            }
            JSONObject data = JSONObject.parseObject(stateBody).getJSONObject("data");
            map.put("baseInfo", data.getJSONObject("baseInfo"));
            map.put("instanceInfoList", data.getJSONArray("instanceLogInfoList"));
            return RetResponse.makeOKRsp(map);
        } catch (Exception e) {
            return ErrorUtil.generalException(e);
        }
    }

    /**
     * 获取流程审批人
     *
     * @param instanceId 流程id
     * @return RetResult
     */
    @RequestMapping(value = "/getParticipants")
    @ResponseBody
    public RetResult getParticipants(@RequestParam String instanceId) {
        try {
            List<Map<String, String>> participants = starChargeBpmService.getParticipants(instanceId);
            return RetResponse.makeOKRsp(participants);
        } catch (Exception e) {
            return ErrorUtil.generalException(e);
        }
    }

    /**
     * 获取当前审批人是否有协办在进行中
     * @param instanceId
     * @param creator
     * @return
     */
    @RequestMapping(value = "/isWorkItemAssist")
    @ResponseBody
    public RetResult isWorkItemAssist(@RequestParam String instanceId,@RequestParam String creator) {
        try {
            Boolean itemAssist = starChargeBpmService.isWorkItemAssist(instanceId,creator);
            return RetResponse.makeOKRsp(itemAssist);
        } catch (Exception e) {
            return ErrorUtil.generalException(e);
        }
    }


}